package cool.webstudy.admin.filter.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import cool.webstudy.admin.constant.CryptoConstant;
import cool.webstudy.admin.constant.TokenPayloadKeyConstant;
import cool.webstudy.admin.constant.enums.rescode.AuthResCodeEnum;
import cool.webstudy.admin.constant.enums.rescode.UserResCodeEnum;
import cool.webstudy.admin.model.dto.user.UserDetailInfoDTO;
import cool.webstudy.admin.model.po.user.UserPO;
import cool.webstudy.admin.service.UserService;
import cool.webstudy.admin.utils.JwtUtil;
import cool.webstudy.admin.utils.RequestUtil;
import cool.webstudy.admin.utils.common.Result;
import cool.webstudy.admin.utils.crypto.AESUtil;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Objects;

@Slf4j
@Component
public class JWTAuthenticationFilter extends OncePerRequestFilter implements Ordered {
    @Value("#{'${security.url_white_list}'.split(',')}")
    private String[] urlWhiteList;
    @Autowired
    private UserService userService;
    @Override
    public int getOrder() {
        return 0; // 这里设置过滤器的顺序值，值越小优先级越高
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.setHeader("content-type", "application/json;charset=UTF-8");
        //遍历白名单并构建路径匹配对象数组与请求路径匹配，如果匹配成功则放行
        for (int i = 0; i < urlWhiteList.length; i++) {
            AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(urlWhiteList[i]);
            if (antPathRequestMatcher.matches(request)) {
                filterChain.doFilter(request, response);
                return;
            }
        }
        //如果不是白名单中的接口，则要求携带token
        String token = request.getHeader("Authorization");
        if(StringUtils.isEmpty(token)){
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.writeValue(response.getOutputStream(), Result.failure(AuthResCodeEnum.RC_NOT_FOUND_TOKEN));
            return;
        }
        //验证token
        JwtUtil jwtUtil = new JwtUtil();
        if(token.startsWith("Bearer ")){
            token = token.substring(7);
        }
        AuthResCodeEnum result = jwtUtil.isVerify(token);
        if (Objects.nonNull(result)){
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.writeValue(response.getOutputStream(), Result.failure(result));
            return;
        }
        //解析出token的payload
        Claims claims = jwtUtil.decode(token);
        String userUnCode = claims.get(TokenPayloadKeyConstant.USERINFO).toString();
        userUnCode = AESUtil.decode(userUnCode, CryptoConstant.AES_KEY);
        //检测用户信息合法性
        UserPO userPO = userService.isExist(userUnCode);
        if (Objects.isNull(userPO)){
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.writeValue(response.getOutputStream(), Result.failure(UserResCodeEnum.RC_USER_NOT_EXIST));
            return;
        }
        UserDetailInfoDTO userDetailInfoDTO = new UserDetailInfoDTO();
        userDetailInfoDTO.setId(userPO.getId());
        userDetailInfoDTO.setUnCode(userPO.getUnCode());
        userDetailInfoDTO.setAccount(userPO.getAccount());
        userDetailInfoDTO.setUsername(userPO.getUsername());
        userDetailInfoDTO.setRole(userPO.getRole());
        userDetailInfoDTO.setSourceIP(RequestUtil.getRequestIp(request));
        SecurityContextHolder.getContext().setAuthentication(UsernamePasswordAuthenticationToken.authenticated(userDetailInfoDTO
                , null, null));
        filterChain.doFilter(request, response);
    }
}
